/**
 * 视频缓存服务
 * 提供视频预加载、缓存管理、内存优化等功能
 * 适用于uni-app多平台（APP、小程序、H5）
 */

class VideoCacheService {
  constructor() {
    this.cacheMap = new Map(); // 缓存映射表
    this.downloadingMap = new Map(); // 下载进度映射表
    this.cacheSize = 0; // 当前缓存大小
    this.maxCacheSize = 100 * 1024 * 1024; // 最大缓存大小 100MB
    this.maxCacheCount = 20; // 最大缓存数量
    this.cacheStorageKey = 'video_cache_storage'; // 本地存储键名
    this.enablePersistence = true; // 是否启用持久化存储
    this.compressionLevel = 0.8; // 压缩级别
    
    // 平台检测
    this.platform = this.detectPlatform();
    this.supportsFileSystem = this.platform === 'app';
    
    // 性能监控
    this.performanceMetrics = {
      cacheHits: 0,
      cacheMisses: 0,
      downloadTime: 0,
      averageDownloadTime: 0
    };
  }

  /**
   * 检测运行平台
   */
  detectPlatform() {
    // #ifdef APP-PLUS
    return 'app';
    // #endif
    
    // #ifdef MP-WEIXIN
    return 'mp-weixin';
    // #endif
    
    // #ifdef MP-ALIPAY
    return 'mp-alipay';
    // #endif
    
    // #ifdef H5
    return 'h5';
    // #endif
    
    return 'unknown';
  }

  /**
   * 初始化缓存服务
   */
  async init() {
    console.log(`[VideoCacheService] 初始化中... 平台: ${this.platform}`);
    
    try {
      // 从本地存储恢复缓存映射
      await this.loadCacheFromStorage();
      
      // 清理过期缓存
      await this.cleanExpiredCache();
      
      // 验证缓存文件完整性
      await this.validateCacheIntegrity();
      
      console.log(`[VideoCacheService] 初始化完成，当前缓存: ${this.cacheMap.size} 个文件`);
      
    } catch (error) {
      console.error('[VideoCacheService] 初始化失败:', error);
    }
  }

  /**
   * 缓存视频
   * @param {string} videoUrl - 视频URL
   * @param {Object} options - 缓存选项
   */
  async cache(videoUrl, options = {}) {
    const {
      priority = 1, // 优先级 1-10
      quality = 'high', // 质量: low, medium, high
      maxRetries = 3, // 最大重试次数
      timeout = 30000 // 超时时间
    } = options;

    // 检查是否已经缓存
    if (this.cacheMap.has(videoUrl)) {
      const cacheInfo = this.cacheMap.get(videoUrl);
      if (await this.isCacheValid(cacheInfo)) {
        this.performanceMetrics.cacheHits++;
        console.log(`[VideoCacheService] 缓存命中: ${videoUrl}`);
        return cacheInfo.localPath;
      } else {
        // 缓存无效，删除
        await this.removeFromCache(videoUrl);
      }
    }

    // 检查是否正在下载
    if (this.downloadingMap.has(videoUrl)) {
      console.log(`[VideoCacheService] 视频正在下载中: ${videoUrl}`);
      return await this.downloadingMap.get(videoUrl);
    }

    // 开始下载并缓存
    const downloadPromise = this.downloadAndCache(videoUrl, { priority, quality, maxRetries, timeout });
    this.downloadingMap.set(videoUrl, downloadPromise);

    try {
      const result = await downloadPromise;
      this.downloadingMap.delete(videoUrl);
      return result;
    } catch (error) {
      this.downloadingMap.delete(videoUrl);
      throw error;
    }
  }

  /**
   * 下载并缓存视频
   */
  async downloadAndCache(videoUrl, options) {
    const startTime = Date.now();
    this.performanceMetrics.cacheMisses++;

    try {
      console.log(`[VideoCacheService] 开始下载视频: ${videoUrl}`);

      // 检查缓存空间
      await this.ensureCacheSpace();

      const localPath = await this.downloadVideo(videoUrl, options);
      
      // 获取文件信息
      const fileInfo = await this.getFileInfo(localPath);
      
      // 添加到缓存映射
      const cacheInfo = {
        url: videoUrl,
        localPath: localPath,
        size: fileInfo.size,
        createdAt: Date.now(),
        lastAccessed: Date.now(),
        accessCount: 1,
        quality: options.quality
      };

      this.cacheMap.set(videoUrl, cacheInfo);
      this.cacheSize += fileInfo.size;

      // 保存缓存映射到本地存储
      await this.saveCacheToStorage();

      const downloadTime = Date.now() - startTime;
      this.updatePerformanceMetrics(downloadTime);

      console.log(`[VideoCacheService] 视频缓存完成: ${videoUrl}, 耗时: ${downloadTime}ms`);
      
      return localPath;

    } catch (error) {
      console.error(`[VideoCacheService] 视频缓存失败: ${videoUrl}`, error);
      throw error;
    }
  }

  /**
   * 下载视频文件
   */
  async downloadVideo(videoUrl, options) {
    const { timeout = 30000, maxRetries = 3 } = options;
    
    let lastError = null;
    
    for (let retry = 0; retry < maxRetries; retry++) {
      try {
        if (this.supportsFileSystem) {
          // App端使用文件系统
          return await this.downloadToFileSystem(videoUrl, timeout);
        } else {
          // 小程序和H5使用临时文件
          return await this.downloadToTempFile(videoUrl, timeout);
        }
      } catch (error) {
        lastError = error;
        console.warn(`[VideoCacheService] 下载重试 ${retry + 1}/${maxRetries}:`, error);
        
        if (retry < maxRetries - 1) {
          // 指数退避重试
          await this.delay(Math.pow(2, retry) * 1000);
        }
      }
    }
    
    throw lastError;
  }

  /**
   * App端下载到文件系统
   */
  async downloadToFileSystem(videoUrl, timeout) {
    return new Promise((resolve, reject) => {
      const fileName = this.generateFileName(videoUrl);
      const savePath = `${plus.io.PRIVATE_DOC}/videos/${fileName}`;
      
      // 确保目录存在
      const videoDir = plus.io.PRIVATE_DOC + '/videos';
      plus.io.resolveLocalFileSystemURL(videoDir, () => {}, () => {
        plus.io.requestFileSystem(plus.io.PRIVATE_DOC, (fs) => {
          fs.root.getDirectory('videos', { create: true });
        });
      });

      const downloadTask = plus.downloader.createDownload(videoUrl, {
        filename: savePath,
        timeout: timeout
      }, (download, status) => {
        if (status === 200) {
          resolve(savePath);
        } else {
          reject(new Error(`下载失败，状态码: ${status}`));
        }
      });

      downloadTask.start();

      // 超时处理
      setTimeout(() => {
        downloadTask.abort();
        reject(new Error('下载超时'));
      }, timeout);
    });
  }

  /**
   * 小程序和H5下载到临时文件
   */
  async downloadToTempFile(videoUrl, timeout) {
    return new Promise((resolve, reject) => {
      const downloadTask = uni.downloadFile({
        url: videoUrl,
        timeout: timeout,
        success: (res) => {
          if (res.statusCode === 200) {
            resolve(res.tempFilePath);
          } else {
            reject(new Error(`下载失败，状态码: ${res.statusCode}`));
          }
        },
        fail: (error) => {
          reject(error);
        }
      });

      // 监听下载进度
      downloadTask.onProgressUpdate((progress) => {
        console.log(`[VideoCacheService] 下载进度: ${progress.progress}%`);
      });
    });
  }

  /**
   * 获取缓存的视频
   */
  async get(videoUrl) {
    if (!this.cacheMap.has(videoUrl)) {
      return null;
    }

    const cacheInfo = this.cacheMap.get(videoUrl);
    
    // 验证缓存是否有效
    if (await this.isCacheValid(cacheInfo)) {
      // 更新访问信息
      cacheInfo.lastAccessed = Date.now();
      cacheInfo.accessCount++;
      
      this.performanceMetrics.cacheHits++;
      return cacheInfo.localPath;
    } else {
      // 缓存无效，删除
      await this.removeFromCache(videoUrl);
      return null;
    }
  }

  /**
   * 验证缓存是否有效
   */
  async isCacheValid(cacheInfo) {
    try {
      if (this.supportsFileSystem) {
        // App端检查文件是否存在
        return await this.fileExists(cacheInfo.localPath);
      } else {
        // 小程序和H5的临时文件通常不持久，需要重新下载
        return false;
      }
    } catch (error) {
      console.warn('[VideoCacheService] 缓存验证失败:', error);
      return false;
    }
  }

  /**
   * 检查文件是否存在
   */
  async fileExists(filePath) {
    return new Promise((resolve) => {
      // #ifdef APP-PLUS
      plus.io.resolveLocalFileSystemURL(filePath, () => {
        resolve(true);
      }, () => {
        resolve(false);
      });
      // #endif
      
      // #ifndef APP-PLUS
      resolve(false);
      // #endif
    });
  }

  /**
   * 获取文件信息
   */
  async getFileInfo(filePath) {
    return new Promise((resolve, reject) => {
      // #ifdef APP-PLUS
      plus.io.resolveLocalFileSystemURL(filePath, (entry) => {
        entry.getMetadata((metadata) => {
          resolve({
            size: metadata.size,
            modificationTime: metadata.modificationTime
          });
        }, reject);
      }, reject);
      // #endif
      
      // #ifndef APP-PLUS
      // 小程序和H5无法准确获取文件大小，使用估算值
      resolve({
        size: 1024 * 1024, // 1MB估算
        modificationTime: new Date()
      });
      // #endif
    });
  }

  /**
   * 确保缓存空间充足
   */
  async ensureCacheSpace() {
    // 检查缓存数量
    if (this.cacheMap.size >= this.maxCacheCount) {
      await this.evictLeastRecentlyUsed();
    }

    // 检查缓存大小
    if (this.cacheSize >= this.maxCacheSize) {
      await this.evictLeastRecentlyUsed();
    }
  }

  /**
   * 使用LRU策略清理缓存
   */
  async evictLeastRecentlyUsed() {
    const cacheEntries = Array.from(this.cacheMap.entries());
    
    // 按最后访问时间排序
    cacheEntries.sort((a, b) => a[1].lastAccessed - b[1].lastAccessed);

    // 清理最老的缓存
    const evictCount = Math.max(1, Math.floor(this.maxCacheCount * 0.2));
    
    for (let i = 0; i < evictCount && i < cacheEntries.length; i++) {
      const [url, cacheInfo] = cacheEntries[i];
      await this.removeFromCache(url);
      console.log(`[VideoCacheService] 清理缓存: ${url}`);
    }
  }

  /**
   * 从缓存中删除
   */
  async removeFromCache(videoUrl) {
    if (!this.cacheMap.has(videoUrl)) {
      return;
    }

    const cacheInfo = this.cacheMap.get(videoUrl);
    
    try {
      // 删除文件
      if (this.supportsFileSystem) {
        await this.deleteFile(cacheInfo.localPath);
      }
      
      // 更新缓存大小
      this.cacheSize -= cacheInfo.size;
      
      // 从映射中删除
      this.cacheMap.delete(videoUrl);
      
      // 保存更新后的缓存映射
      await this.saveCacheToStorage();
      
    } catch (error) {
      console.warn(`[VideoCacheService] 删除缓存失败: ${videoUrl}`, error);
    }
  }

  /**
   * 删除文件
   */
  async deleteFile(filePath) {
    return new Promise((resolve) => {
      // #ifdef APP-PLUS
      plus.io.resolveLocalFileSystemURL(filePath, (entry) => {
        entry.remove(resolve, resolve);
      }, resolve);
      // #endif
      
      // #ifndef APP-PLUS
      resolve();
      // #endif
    });
  }

  /**
   * 清理过期缓存
   */
  async cleanExpiredCache() {
    const maxAge = 7 * 24 * 60 * 60 * 1000; // 7天
    const now = Date.now();
    
    const expiredKeys = [];
    
    for (const [url, cacheInfo] of this.cacheMap.entries()) {
      if (now - cacheInfo.createdAt > maxAge) {
        expiredKeys.push(url);
      }
    }
    
    for (const url of expiredKeys) {
      await this.removeFromCache(url);
    }
    
    if (expiredKeys.length > 0) {
      console.log(`[VideoCacheService] 清理过期缓存: ${expiredKeys.length} 个`);
    }
  }

  /**
   * 验证缓存完整性
   */
  async validateCacheIntegrity() {
    const invalidKeys = [];
    
    for (const [url, cacheInfo] of this.cacheMap.entries()) {
      if (!(await this.isCacheValid(cacheInfo))) {
        invalidKeys.push(url);
      }
    }
    
    for (const url of invalidKeys) {
      this.cacheMap.delete(url);
    }
    
    if (invalidKeys.length > 0) {
      console.log(`[VideoCacheService] 清理无效缓存: ${invalidKeys.length} 个`);
      await this.saveCacheToStorage();
    }
  }

  /**
   * 从本地存储加载缓存映射
   */
  async loadCacheFromStorage() {
    try {
      const cacheData = uni.getStorageSync(this.cacheStorageKey);
      if (cacheData && cacheData.cacheMap) {
        this.cacheMap = new Map(cacheData.cacheMap);
        this.cacheSize = cacheData.cacheSize || 0;
        this.performanceMetrics = { ...this.performanceMetrics, ...cacheData.performanceMetrics };
      }
    } catch (error) {
      console.warn('[VideoCacheService] 加载缓存映射失败:', error);
    }
  }

  /**
   * 保存缓存映射到本地存储
   */
  async saveCacheToStorage() {
    try {
      const cacheData = {
        cacheMap: Array.from(this.cacheMap.entries()),
        cacheSize: this.cacheSize,
        performanceMetrics: this.performanceMetrics,
        lastUpdated: Date.now()
      };
      
      uni.setStorageSync(this.cacheStorageKey, cacheData);
    } catch (error) {
      console.warn('[VideoCacheService] 保存缓存映射失败:', error);
    }
  }

  /**
   * 生成文件名
   */
  generateFileName(videoUrl) {
    const hash = this.simpleHash(videoUrl);
    const extension = this.getFileExtension(videoUrl) || 'mp4';
    return `video_${hash}.${extension}`;
  }

  /**
   * 简单哈希函数
   */
  simpleHash(str) {
    let hash = 0;
    for (let i = 0; i < str.length; i++) {
      const char = str.charCodeAt(i);
      hash = ((hash << 5) - hash) + char;
      hash = hash & hash; // 转换为32位整数
    }
    return Math.abs(hash).toString(16);
  }

  /**
   * 获取文件扩展名
   */
  getFileExtension(url) {
    const match = url.match(/\.([^.?]+)(?:\?.*)?$/);
    return match ? match[1] : null;
  }

  /**
   * 更新性能指标
   */
  updatePerformanceMetrics(downloadTime) {
    this.performanceMetrics.downloadTime += downloadTime;
    const totalDownloads = this.performanceMetrics.cacheMisses;
    this.performanceMetrics.averageDownloadTime = this.performanceMetrics.downloadTime / totalDownloads;
  }

  /**
   * 获取缓存统计信息
   */
  getCacheStats() {
    const hitRate = this.performanceMetrics.cacheHits / 
      (this.performanceMetrics.cacheHits + this.performanceMetrics.cacheMisses) * 100;
    
    return {
      cacheCount: this.cacheMap.size,
      cacheSize: this.cacheSize,
      maxCacheSize: this.maxCacheSize,
      hitRate: hitRate.toFixed(2),
      averageDownloadTime: this.performanceMetrics.averageDownloadTime.toFixed(2),
      ...this.performanceMetrics
    };
  }

  /**
   * 清空所有缓存
   */
  async clearAll() {
    for (const url of this.cacheMap.keys()) {
      await this.removeFromCache(url);
    }
    
    this.cacheMap.clear();
    this.cacheSize = 0;
    
    // 重置性能指标
    this.performanceMetrics = {
      cacheHits: 0,
      cacheMisses: 0,
      downloadTime: 0,
      averageDownloadTime: 0
    };
    
    await this.saveCacheToStorage();
    console.log('[VideoCacheService] 所有缓存已清空');
  }

  /**
   * 延迟函数
   */
  delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  /**
   * 预热缓存（批量下载）
   */
  async warmupCache(videoUrls, options = {}) {
    const { 
      concurrency = 3, // 并发数
      priority = 1 
    } = options;
    
    console.log(`[VideoCacheService] 开始预热缓存: ${videoUrls.length} 个视频`);
    
    const chunks = [];
    for (let i = 0; i < videoUrls.length; i += concurrency) {
      chunks.push(videoUrls.slice(i, i + concurrency));
    }
    
    for (const chunk of chunks) {
      const promises = chunk.map(url => 
        this.cache(url, { priority }).catch(error => {
          console.warn(`[VideoCacheService] 预热失败: ${url}`, error);
          return null;
        })
      );
      
      await Promise.all(promises);
    }
    
    console.log('[VideoCacheService] 缓存预热完成');
  }

  /**
   * 获取下载进度
   */
  getDownloadProgress(videoUrl) {
    return this.downloadingMap.has(videoUrl);
  }
}

export default VideoCacheService;